package com.kitty.mina.filter;

import com.kitty.common.utils.ConcurrentHashSet;
import com.kitty.mina.ModuleCounter;
import com.kitty.mina.ModuleCounterSchedule;
import com.kitty.mina.Modules;
import com.kitty.mina.cache.SessionUtils;
import com.kitty.mina.message.Message;
import com.kitty.mina.session.SessionManager;
import com.kitty.mina.session.SessionProperties;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.validation.constraints.NotNull;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IoSession;

/**
 * 发包计次
 */
@Slf4j
public class ModuleCounterFilter extends IoFilterAdapter {
    /**
     * 连接后多少毫秒开始检测是否有包
     */
    public static final Integer G_IDLE_TIME = 3000;

    public static final String BAN_SHELL = "iptables -I INPUT -s %s -j DROP";

    /**
     * 黑名单IP
     */
    public static final Set<String> G_BAN_IP = new ConcurrentHashSet<>(100000);

    /**
     * 全局 未check状态计次
     */
    public static final AtomicInteger G_UNCHECKED_PLAYER = new AtomicInteger(0);

    /**
     * 全局 最多未检测的数量 超过该数量拒绝所有连接 防止大量连接打入
     */
    public static final Integer G_MAX_UNCHECKED_CONN = 100;

    /**
     * 未检测玩家最多等待时间 登录后超过该值要被踢下线
     */
    public static final Integer G_MAX_WAIT_TIME = 30 * 1000;

    /**
     * 最少包个数
     */
    public static final Integer G_MIN_PACKET_COUNT = 5;

    /**
     * 多样性数量值达到当前值 则不检测心跳数
     */
    public static final Integer G_JUMP_HEARTBEAT_CHECK = 7;


    /**
     * 规则 最小协议类型数量
     */
    public static final Integer R_MIN_MODULE_COUNT = 2;

    /**
     * 规则 必须含有的协议类型
     */
    public static final Set<Integer> R_MUST_CMD = new HashSet<>();

    {
        /*心跳*/
        R_MUST_CMD.add(Modules.CMD_ECHO);
        /*登录*/
        R_MUST_CMD.add(Modules.CMD_LOGIN);
    }

    /**
     * 加入黑名单
     * @param session
     */
    public static void banIp(@NotNull IoSession session) {
        String clientIP = ((InetSocketAddress)session.getRemoteAddress()).getAddress().getHostAddress();
        ModuleCounterSchedule.disconnected(session);
//        log.error("登录次数异常,加入黑名单 {}", clientIP);
//        G_BAN_IP.add(clientIP);
//        execShell(String.format(BAN_SHELL, clientIP));
    }

    public static void execShell(String shell){
        try {
            Runtime.getRuntime().exec(shell);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session, Object packet) {
        Message message = (Message) packet;
        //Role role = SessionUtils.getRoleBySession(session);
        //获取记录对象
//        ModuleCounter counter = getCounter(session);
        //计次
//        int c = count(message.getModule(), counter);
        //判断是否大量登录打入
//        if (message.getModule() == Modules.CMD_L_ACCOUNT && c > 5) {
//            banIp(session);
//            return;
//        }
        //检查当前非正常counter 是否转换为合法玩家
//        if (!counter.isChecked()) {
//            counter.setChecked(rule(counter));
//            if (counter.isChecked()) {
//                int count = G_UNCHECKED_PLAYER.decrementAndGet();
//                log.error("[MODULE_COUNTER] 转换为合法玩家 {}, 当前未合法玩家 {}", counter, count);
//            }
//        }
//        log.error("[MODULE_COUNTER] counter: {}", counter);
        //下个filter
        nextFilter.messageReceived(session, message);
    }

    /**
     * 获取计数器
     *
     * @param session
     */
//    public static ModuleCounter getCounter(IoSession session) {
//        SessionManager sessionMgr = SessionManager.INSTANCE;
//        ModuleCounter counter = sessionMgr
//                .getSessionAttr(session, SessionProperties.MODULE_COUNTER, ModuleCounter.class);
//        if (counter == null) {
//            counter = new ModuleCounter();
//            counter.setLoginTime(System.currentTimeMillis());
//            session.setAttribute(SessionProperties.MODULE_COUNTER, counter);
//            //增加unchecked数量
//            int count = G_UNCHECKED_PLAYER.incrementAndGet();
//            if (!canConnect()) {
////                dumpUnchecked();
//                log.error("[MODULE_COUNTER] 当前变更为不可连接,当前未合法数 {}", count);
//            }
//        }
//
//        return counter;
//    }

    /**
     * 打印unchecked counter
     */
    public static void dumpUnchecked() {
//        StringBuilder sb = new StringBuilder();
//        sb.append("[MODULE_COUNTER] dumpUnchecked ");
//        sb.append(SessionUtils.getSessionList().size());
//        sb.append("unchecked数据: \n");
//        SessionUtils.getSessionList().values().forEach(e -> {
//            ModuleCounter counter = ModuleCounterFilter.getCounter(e);
//            if (!counter.isChecked()) {
//                sb.append(counter.toString() + "\n");
//            }
//        });

//        log.error(sb.toString());
    }

    /**
     * 打印所有counter
     */
    public static void dumpAll() {
//        StringBuilder sb = new StringBuilder();
//        sb.append("[MODULE_COUNTER] dumpAll ");
//        sb.append(SessionUtils.getSessionList().size());
//        sb.append("all counter数据: \n");
//        SessionUtils.getSessionList().values().forEach(e -> {
//            ModuleCounter counter = ModuleCounterFilter.getCounter(e);
//            sb.append(counter.toString() + "\n");
//        });
//
//        log.error(sb.toString());
    }

    /**
     * 协议请求计次
     *
     * @param cmd
     * @param counter
     */
    private static int count(int cmd, ModuleCounter counter) {
        counter.setLastPackTime(System.currentTimeMillis());
        counter.getCount().getAndIncrement();
        Map<Integer, AtomicInteger> counterMap = counter.getCounterMap();
        if (!counterMap.containsKey(cmd)) {
            synchronized (counterMap) {
                if (!counterMap.containsKey(cmd)) {
                    counterMap.put(cmd, new AtomicInteger(0));
                }
            }
        }

        return counterMap.get(cmd).incrementAndGet();
    }


    /**
     * 转行状态规则
     */
    public static boolean rule(ModuleCounter counter) {
        Map<Integer, AtomicInteger> counterMap = counter.getCounterMap();

        /**
         * 检查包多样性
         */
        if (counterMap.size() < R_MIN_MODULE_COUNT) {
            return false;
        }

        /**
         * 检查包个数
         */
        if (counter.getCount().get() < G_MIN_PACKET_COUNT) {
            return false;
        }

        /**
         * 仍然未包含的包
         */
        long cmdCount = R_MUST_CMD.parallelStream().filter(e -> !counterMap.containsKey(e)).count();

        return cmdCount == 0;
    }

    /**
     * 是否能连接
     */
    public static boolean canConnect() {
        return G_UNCHECKED_PLAYER.get() < G_MAX_UNCHECKED_CONN;
    }
}
